import { Connector } from "../connector/Connector";
import { FrontendSession } from "../session/FrontendSession";
import { RpcHandler } from "../handler/RpcHandler";
import { StructCoder, StructValueType as SVT } from "k-coder";

/**
 * 杂项配置
 */
export const miscCfg = {
    svrToken: "im svr",
    cliToken: "im cli",
    serverReconnectTime: 2 * 1000,
    rpcCallTimeout: 5 * 1000,
    msgHandlerTimeout: 5 * 1000,
    RegTimeout: 5 * 1000,
    heartbeatTime: 60 * 1000,
    heartbeatTimeout: 60 * 1000,
    dataMaxLenUnreg: 1024,
    dataMaxLen: 2 * 1024 * 1024,
    serversPath: "./servers/",
    reloadMsgCfgPath: "",
    autoReloadHandler: false,
    ssl: null as { cert: string, key: string },
    msgCoder: null as IMsgCoder,
    cliTimeout: 60 * 1000,
    connectorConstructor: null as typeof Connector,
    logger: null as (level: LogLevel, msg: string) => void,
    onCmd: null as (cmd: string) => { code: number, msg?: string, data?: any },
    onClient: null as (sess: FrontendSession) => void,
    onClientClose: null as (sess: FrontendSession, err?: Error) => void,
    onStop: null as () => void | Promise<void>,
    msgFilter: (() => false) as (sess: FrontendSession, msgId: number) => boolean,
    onAddSvr: null as (svr: SvrInfo) => void,
    onRemoveSvr: null as (svr: SvrInfo) => void,
}

/**
 * 服务器配置
 */
export interface SvrCfg {
    [env: string]: {
        master: { id: string, host: string, port?: number, args?: any },
        servers: {
            [stype: string]: {
                id: string, host: string, port: number, clientPort?: number, args?: any
            }[]
        }
    }
}

/**
 * 消息配置
 */
export interface MsgCfg {
    [msgId: number]: string,
}

/**
 * App配置
 */
export interface AppCfg {
    svrCfg: SvrCfg,
    msgCfg: MsgCfg
}

/**
 * 服务器信息
 */
export interface SvrInfo {
    /** 服务器id */
    readonly id: string,
    /** 服务器类型 */
    readonly type: string,
    /** 服务器地址 */
    readonly host: string,
    /** 服务器端口 */
    readonly port: number,
    /** 是否是前端服务器 */
    readonly isFrontend: boolean,
    /** 服务器对客户端端口 */
    readonly clientPort?: number,
    /** 额外参数 */
    readonly args?: { [key: string]: any }
}

/**
 * 日志级别
 */
export const enum LogLevel {
    debug = "debug",
    info = "info",
    warn = "warn",
    error = "error"
}

/**
 * 会话接口
 */
export interface ISession {
    /** 客户端id */
    uid: number;
    /** 前端服务器id */
    sid: string;
    /** 键值对数据 前端服务器会传递给后端服务器 后端服务器设置不会影响前端  */
    setting: { [key: string | number]: any };
}

/**
 * 会话编解码
 */
export const sessCoder = new StructCoder(
    [
        ["uid", SVT.ulong],
        ["sid", SVT.str],
        ["setting", SVT.obj],
    ]
);

/**
 * 消息编解码接口
 */
export interface IMsgCoder {
    /** 编码 */
    encode(msgId: number, msg?: any): Buffer;
    /** 解码 */
    decode(data: Buffer): { msgId: number, msg?: any };
    /** 只解码出消息id */
    decodeMsgId(data: Buffer): { msgId: number, msgBuf: Buffer };
    /** 解码消息 */
    decodeMsgBuf(msgId: number, msgBuf: Buffer): any;
}

/**
 * Scoket注册消息
 */
export interface ScoketRegMsg {
    token: string,
    sid?: string
}

/**
 * Server与Master通信的消息Id
 */
export const enum SvrMsgId {
    regOk,
    heartbeat,
    svrAdd,
    svrRemove,
    cliRes,
    cmd,
    stop,
    reloadMsgCfg,
    reloadMsg,
    reloadRpc,
}

/**
 * Server与Master通信的消息数据
 */
export type SvrMsg<Msg extends SvrMsgId = SvrMsgId> = {
    [SvrMsgId.regOk]: string[],
    [SvrMsgId.heartbeat]: undefined,
    [SvrMsgId.svrAdd]: string,
    [SvrMsgId.svrRemove]: string,
    [SvrMsgId.cliRes]: { cid: number, sess: number, sid: string, res?: { code: number, msg?: string, data?: any } },
    [SvrMsgId.cmd]: { cid: number, sess: number, cmd: string },
    [SvrMsgId.stop]: { cid?: number, sess?: number },
    [SvrMsgId.reloadMsgCfg]: { cid: number, sess: number, reload: string },
    [SvrMsgId.reloadMsg]: { cid: number, sess: number, reload: string },
    [SvrMsgId.reloadRpc]: { cid: number, sess: number, reload: string },
}[Msg]

/**
 * Cli与Master通信的消息Id
 */
export const enum CliMsgId {
    err,
    regOk,
    heartbeat,
    cmd,
    stop,
    reload,
    result,
}

/**
 * Cli与Master通信的消息数据
 */
export type CliMsg<Msg extends CliMsgId = CliMsgId> = {
    [CliMsgId.err]: string,
    [CliMsgId.regOk]: string[],
    [CliMsgId.heartbeat]: undefined,
    [CliMsgId.result]: { sess: number, resArr: { sid: string, res: { code: number, msg?: string, data?: any } }[], timeout?: boolean },
    [CliMsgId.cmd]: { sess: number, cmd: string, all?: boolean, sids?: string[], stypes?: string[] },
    [CliMsgId.stop]: { sess: number, },
    [CliMsgId.reload]: { sess: number, reload: string },
}[Msg]


/**
 * Rpc通信消息Id
 */
export const enum RpcMsgId {
    regOk,
    heartbeat,
    rpcCall,
    rpcCallRes,
    syncSetting,
    msgSend,
    msgHandler
}

/**
 * Rpc通信消息数据
 */
export type RpcMsg<Msg extends RpcMsgId = RpcMsgId> = {
    [RpcMsgId.regOk]: undefined,
    [RpcMsgId.heartbeat]: undefined,
    [RpcMsgId.rpcCall]: { id: number, handler: string, func: string, args?: any[], notify?: boolean },
    [RpcMsgId.rpcCallRes]: { id: number, res: RpcCallRes },
    [RpcMsgId.syncSetting]: { uid: number, setting: { [key: string | number]: any }, deleteKeys?: string[] },
    [RpcMsgId.msgSend]: { uid?: number, uids?: number[], data?: Uint8Array, datas?: Uint8Array[] },
    [RpcMsgId.msgHandler]: { sessBuf: Uint8Array, data: Uint8Array }
}[Msg]

/**
 * Rpc调用错误
 */
export interface RpcCallError {
    /** -1:未知错误 -2:调用超时 other:自定义错误 */
    code: number,
    msg: string
}

/**
 * Rpc调用结果,仅通知时该结构为{}
 */
export interface RpcCallRes<T = any> {
    err?: RpcCallError,
    data?: T
}

type RpcPromisify<T> = T extends (...args: infer P) => infer R ? R extends Promise<RpcCallRes> ? (...args: P) => R : (...args: P) => Promise<R> : never;

/**
 * RpcHandler代理
 */
export type RpcHandlerProxy<T extends RpcHandler = RpcHandler> = { [K in keyof T as T[K] extends (...args: any[]) => RpcCallRes | Promise<RpcCallRes> ? K : never]: RpcPromisify<T[K]> };

declare global {
    interface Rpc {
        [stype: string]: {
            [rpcName: string]: RpcHandlerProxy | any
        }
    }
}

/**
 * Socket代理
 */
export interface ISocket {
    /** 原生scoket */
    socket: any;
    /** 远程ip地址 */
    remoteAddress: string;
    /** 数据包大小限制 */
    dataMaxLen: number;

    /**
     * 发送数据
     * @param data 
     */
    send(data: Buffer): void;

    /**
     * 监听事件
     * @param event 
     * @param onData 
     */
    on(event: "data", onData: (data: Buffer) => any): void;
    on(event: "close", onClose: () => any): void;
    on(event: "error", onError: (err: Error) => any): void;
    on(event: "data" | "close" | "error", listener: (...args: any[]) => any): void;

    /**
     * 取消监听
     * @param event 
     * @param listener 
     */
    off(event: "data" | "close" | "error", listener: (...args: any[]) => any): void;

    /**
     * 关闭连接
     */
    close(): void;
}